package com.zmn.plat.business.impl.product;

import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.plat.business.interfaces.channel.ChannelCategBService;
import com.zmn.plat.business.interfaces.channel.ChannelServiceCategoryBService;
import com.zmn.plat.business.interfaces.product.ProductCache;
import com.zmn.plat.business.interfaces.product.ProductDetailsBService;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.dto.product.ProductDIO;
import com.zmn.plat.common.dto.product.base.ProductBaseDRO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.category.ServCategAndCategTwoQuery;
import com.zmn.plat.model.entity.channel.ChannelIdAndName;
import com.zmn.plat.model.entity.channel.ChannelServProduct;
import com.zmn.plat.model.entity.product.FicoCategory;
import com.zmn.plat.model.entity.product.ProductQuery;
import com.zmn.plat.model.entity.servcategory.ServAssCategoryQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.vo.product.ProductAllMsgVO;
import com.zmn.plat.model.vo.servcategory.ServAssCategoryVO;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.channel.ChannelServProductService;
import com.zmn.plat.services.interfaces.channel.ChannelService;
import com.zmn.plat.services.interfaces.channel.generalproduct.ChannelGeneralProductSwitchService;
import com.zmn.plat.services.interfaces.product.FicoCategoryService;
import com.zmn.plat.services.interfaces.product.ServProductRelationService;
import com.zmn.plat.services.interfaces.product.ServTariffProductRelationService;
import com.zmn.plat.services.interfaces.servcategory.ServAssCategoryService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tanbiao
 * @description
 * @modifier
 * @since 2021/3/16 15:02
 **/
@Service
@Slf4j
public class ProductDetailsBServiceImpl implements ProductDetailsBService {
    @Resource
    ProductCache productCache;
    @Resource
    ServCategoryService servCategoryService;
    @Resource
    BaseCategoryService baseCategoryService;
    @Resource
    ServAssCategoryService servAssCategoryService;
    @Resource
    FicoCategoryService ficoCategoryService;
    @Resource
    ChannelCategBService channelCategBService;
    @Resource
    ChannelService channelService;
    @Resource
    ChannelServiceCategoryBService channelServiceCategoryBService;
    @Resource
    ChannelGeneralProductSwitchService channelGeneralProductSwitchService;
    @Resource
    ServProductRelationService servProductRelationService;
    @Resource
    ServTariffProductRelationService servTariffProductRelationService;
    @Resource
    ChannelServProductService channelServProductService;


    @Override
    @Cacheable(cacheNames = "redis5m", key = "'product:base:dio:'+#p0", unless = "#result == null")
    public List<ProductBaseDRO> listBaseDROByDIO(ProductDIO productDIO) {
        if (Objects.isNull(productDIO)) {
            log.error("#ProductDetailsBService# method： listBaseDROByDIO 参数为空");
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }
        // 根据产品id或者产品ids获取基本信息
        List<ProductBaseDRO> porductByIds = getPorductByIds(productDIO);
        if (CollectionUtil.isNotNullOrEmpty(porductByIds)) {
            return porductByIds;
        }
        // 根据其它条件查询产品信息
        ProductQuery productQuery = new ProductQuery();
        BeanUtils.copyProperties(productDIO, productQuery);
        try {
            filterQuery(productQuery, productDIO);
        } catch (Exception e) {
            log.error("设置查询条件:{}", e.getMessage(), e);
            return Collections.emptyList();
        }

        List<ProductAllMsgVO> productAllMsgVOList = productCache.listProductByQuery(productQuery);

        if (CollectionUtil.isNullOrEmpty(productAllMsgVOList) && Objects.equals(GlobalConsts.YES, productDIO.getDefaultType())) {
            productQuery.setDefaultType(GlobalConsts.NO);
            productAllMsgVOList = productCache.listProductByQuery(productQuery);
        }
        if (CollectionUtil.isNullOrEmpty(productAllMsgVOList)) {
            return Collections.emptyList();
        }
        productAllMsgVOList = filterChannelProductOrOpenCategory(productAllMsgVOList, productQuery.getChannelId(), productQuery.getShowType());
        productAllMsgVOList = filterChannelOpenCategoryByDefaultProducts(productAllMsgVOList, productQuery.getChannelId(), productQuery.getShowType(), productQuery.getDefaultType());
        productAllMsgVOList = filterBizType(productAllMsgVOList, productDIO.getBizType(), productQuery.getShowType(), productQuery.getDefaultType());
        return setProductAllMsgChineseName(productAllMsgVOList, productDIO);

    }


    @Override
    public List<ProductBaseDRO> listEcProduct(Integer bizType) {

        List<ProductBaseDRO> productBaseDROList = new ArrayList<>();
        // 查询产品信息
        ProductQuery productQuery = ProductQuery.builder().status(GlobalConsts.YES).defaultType(GlobalConsts.NO).showType(ProductConsts.EC_PRODUCT_TYPE).build();
        List<ProductAllMsgVO> productAllMsgVOList = productCache.listProductByQuery(productQuery);
        // 过滤产品
        productAllMsgVOList = filterBizType(productAllMsgVOList, bizType, ProductConsts.EC_PRODUCT_TYPE, GlobalConsts.NO);

        Set<Integer> categIds = new HashSet<>();
        productAllMsgVOList.stream().forEach(e -> {
            categIds.add(e.getCategOneId());
            categIds.add(e.getCategId());
        });
        // 查询所有服务分类
        Map<Integer, String> servCategMap = Optional.ofNullable(servCategoryService.listServCategoryAll())
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ServCategory::getCategId, ServCategory::getShowName));

        // 查询所有产品分类
        Map<Integer, String> baseCategoryMap = Optional.ofNullable(baseCategoryService.findByKeys(new ArrayList<>(categIds)))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(BaseCategory::getCategId, BaseCategory::getName));

        productAllMsgVOList.stream().forEach(e -> {
                    ProductBaseDRO dro = new ProductBaseDRO();
                    BeanUtils.copyProperties(e, dro);
                    dro.setServCategName(servCategMap.get(e.getServCategId()));
                    dro.setCategOneName(baseCategoryMap.get(e.getCategOneId()));
                    dro.setCategName(baseCategoryMap.get(e.getCategId()));
                    productBaseDROList.add(dro);
                }
        );
        return productBaseDROList;
    }

    /**
     * 根据产品ids获取产品基本信息
     *
     * @param productDIO 查询实体
     * @return
     */
    private List<ProductBaseDRO> getPorductByIds(ProductDIO productDIO) {
        List<ProductBaseDRO> productBaseDROList = null;
        ProductBaseDRO productBaseDRO;
        ProductAllMsgVO productVO;

        // 如果有产品ID，直接根据产品Id查询基本信息
        if (NumberUtil.isPositiveInteger(productDIO.getProductId())) {
            productVO = productCache.findByKey(productDIO.getProductId());
            if (Objects.isNull(productVO)) {
                return Collections.emptyList();
            }
            productBaseDRO = new ProductBaseDRO();
            BeanUtils.copyProperties(productVO, productBaseDRO);
            productBaseDROList = Arrays.asList(productBaseDRO);
            return productBaseDROList;
        }

        // 如果有产品Id集合，直接根据产品ID集合查询产品基本信息
        if (CollectionUtils.isNotEmpty(productDIO.getProductIdList())) {
            List<ProductAllMsgVO> productAllMsgVOList = productCache.listByKeys(productDIO.getProductIdList());
            if (CollectionUtils.isEmpty(productAllMsgVOList)) {
                return Collections.emptyList();
            }
            productBaseDROList = productAllMsgVOList.stream().map(productAllMsgVO -> {
                ProductBaseDRO productBase = new ProductBaseDRO();
                BeanUtils.copyProperties(productAllMsgVO, productBase);
                return productBase;
            }).collect(Collectors.toList());
            return productBaseDROList;
        }
        return productBaseDROList;
    }

    /**
     * 设置过滤条件（实体间转换）
     *
     * @param productQuery 新查询条件
     * @param productDIO   接口入参
     */
    private void filterQuery(ProductQuery productQuery, ProductDIO productDIO) {
        // 设置业务类型
        if (NumberUtil.isPositiveInteger(productDIO.getBizType())) {
            productQuery.setBizType(productDIO.getBizType().toString());
        }
        // 是否查询默认产品
        if (NumberUtil.isNullOrZero(productDIO.getDefaultType()) && Objects.equals(productDIO.getShowType(), ProductConsts.EC_PRODUCT_TYPE)) {
            productQuery.setDefaultType(GlobalConsts.NO);
        }

        Integer channelId = productDIO.getChannelId();
        if (NumberUtil.isPositiveInteger(channelId)) {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
            productQuery.setChannelId(channelId);
        }

        // 如果渠道和服务分类不为空，需要查询渠道开通的二级分类
        if (Objects.nonNull(channelId) && Objects.nonNull(productDIO.getShowType()) && Objects.nonNull(productDIO.getCityId())) {
            int showType = Objects.equals(ProductConsts.ERP_PRODUCT_TYPE, productDIO.getShowType()) ? ProductConsts.ERP_PRODUCT_TYPE : ProductConsts.EC_PRODUCT_TYPE;
            List<ServCategAndCategTwoQuery> servCategAndCategTwoQueryList =
                    channelCategBService.listServCategAndCategTwoQueryByChannelIdAndShowType(channelId, productDIO.getCityId(), showType);
            if (CollectionUtils.isEmpty(servCategAndCategTwoQueryList)) {
                throw new PlatException("servCategAndCategTwoQueryList is null");
            }
            productQuery.setServCategAndCategTwoQueryList(servCategAndCategTwoQueryList);
        }

    }

    private Map<Integer, ServCategory> setServCategChineseName() {
        //根据条件获取服务分类id名称
        List<ServCategory> byKeys = servCategoryService.listServCategoryAll();
        Map<Integer, ServCategory> map = Optional.ofNullable(byKeys.parallelStream()
                        .collect(Collectors.toMap(ServCategory::getCategId, key -> key, (a, b) -> b)))
                .orElse(null);
        return map;
    }

    private Map<Integer, BaseCategory> setCategChineseName(List<Integer> ids) {
        //根据条件获取服务分类id名称
        if (CollectionUtil.isNotNullOrEmpty(ids)) {
            List<BaseCategory> byKeys = baseCategoryService.findByKeys(ids);
            Map<Integer, BaseCategory> map = Optional.ofNullable(byKeys.parallelStream()
                            .collect(Collectors.toMap(BaseCategory::getCategId, byKey -> byKey, (a, b) -> b)))
                    .orElse(null);
            return map;
        }
        return null;
    }

    private Map<String, String> setCategGropDescName(List<Integer> servCategIds, List<Integer> categOneIds, List<Integer> categIds) {
        //根据条件获取服务分类id名称
        List<ServAssCategoryVO> byKeys = servAssCategoryService.listByQuery(ServAssCategoryQuery.builder()
                .servCategIds(servCategIds).categOneIds(categOneIds).categIds(categIds).build());
        Map<String, String> map = new HashMap<>(byKeys.size());
        for (ServAssCategoryVO key : byKeys) {
            if (Objects.nonNull(key)) {
                map.put(key.getServCategId() + "-" + key.getCategOneId() + "-" + key.getCategId(), key.getDesc());
            }
        }
        return map;
    }

    private Map<Integer, String> setFicoCategChineseName(List<Integer> ids) {
        //根据条件获取服务分类id名称
        if (CollectionUtil.isNotNullOrEmpty(ids)) {
            List<FicoCategory> byKeys = ficoCategoryService.findByKeys(ids);
            Map<Integer, String> map = Optional.ofNullable(byKeys.parallelStream()
                            .collect(Collectors.toMap(FicoCategory::getCategId, byKey -> byKey.getName(), (a, b) -> b)))
                    .orElse(null);
            return map;
        }
        return null;
    }

    private Map<Integer, String> setSubChannelChineseName(List<Integer> ids) {
        //根据条件获取服务分类id名称
        if (CollectionUtil.isNotNullOrEmpty(ids)) {
            List<ChannelIdAndName> byKeys = channelService.listNameByChannelIds(ids);
            Map<Integer, String> map = Optional.ofNullable(byKeys.parallelStream()
                            .collect(Collectors.toMap(ChannelIdAndName::getChannelId, byKey -> byKey.getName(), (a, b) -> b)))
                    .orElse(null);
            return map;
        }
        return null;
    }

    /**
     * 设置各种中文名称
     *
     * @param list       查询后的数据列表
     * @param productDIO 产品查询实体
     * @return
     */
    private List<ProductBaseDRO> setProductAllMsgChineseName(List<ProductAllMsgVO> list, ProductDIO productDIO) {
        List<ProductBaseDRO> productBaseDROList = new ArrayList<>();
        if (CollectionUtil.isNullOrEmpty(list)) {
            return productBaseDROList;
        }
        list = list.stream().map(productAllMsgVO -> {
            if (NumberUtil.isNotNullOrZero(productAllMsgVO.getChannelId())) {
                if (Objects.equals(productAllMsgVO.getProductType(), GlobalConsts.YES)
                        && !productAllMsgVO.getChannelId().equals(productDIO.getChannelId())) {
                    return null;
                }
            }
            return productAllMsgVO;
        }).filter(x -> Objects.nonNull(x)).collect(Collectors.toList());
        if (CollectionUtil.isNullOrEmpty(list)) {
            return productBaseDROList;
        }
        // 服务分类id
        List<Integer> servCategId = list.parallelStream().map(ProductAllMsgVO::getServCategId).distinct().collect(Collectors.toList());
        Map<Integer, ServCategory> servCategMap = setServCategChineseName();
        // 产品一级分类id
        List<Integer> categOneId = list.parallelStream().map(ProductAllMsgVO::getCategOneId).distinct().collect(Collectors.toList());
        // 产品分类id
        List<Integer> categId = list.parallelStream().map(ProductAllMsgVO::getCategId).distinct().collect(Collectors.toList());
        Map<Integer, BaseCategory> categMap = setCategChineseName(ListUtils.union(categOneId, categId));
        Map<String, String> categGrop = setCategGropDescName(servCategId, categOneId, categId);
        // 绩效服务分类id
        List<Integer> ficoCategId = list.parallelStream().map(ProductAllMsgVO::getFicoCtegId).distinct().collect(Collectors.toList());
        Map<Integer, String> ficoCategMap = setFicoCategChineseName(ficoCategId);
        // 获取渠道信息
        List<Integer> channelIds = list.parallelStream().map(ProductAllMsgVO::getChannelId).distinct().collect(Collectors.toList());
        Map<Integer, String> channelMap = setSubChannelChineseName(channelIds);
        list.stream().forEach(msgVO -> {
            ProductBaseDRO vo = new ProductBaseDRO();
            BeanUtils.copyProperties(msgVO, vo);
            ServCategory servCategory = Objects.nonNull(servCategMap) ? Optional.ofNullable(servCategMap.get(vo.getServCategId())).orElse(new ServCategory()) : new ServCategory();
            BaseCategory baseCategory = Objects.nonNull(servCategMap) ? Optional.ofNullable(categMap.get(vo.getCategId())).orElse(new BaseCategory()) : new BaseCategory();

            vo.setServCategName(Objects.equals(GlobalConsts.ERP_PRODUCT_TYPE, productDIO.getShowType()) ? servCategory.getName() : servCategory.getShowName());
            vo.setServSimpleSpell(Objects.equals(GlobalConsts.ERP_PRODUCT_TYPE, productDIO.getShowType()) ? servCategory.getSimpleSpell() : servCategory.getShowSimpleSpell());

            vo.setCategName(baseCategory.getName());
            vo.setCategSimpleSpell(baseCategory.getSimpleSpell());

            baseCategory = Objects.nonNull(servCategMap) ? Optional.ofNullable(categMap.get(vo.getCategOneId())).orElse(new BaseCategory()) : new BaseCategory();
            vo.setCategOneName(baseCategory.getName());
            vo.setCategOneSimpleSpell(baseCategory.getSimpleSpell());

            vo.setDetailName(Objects.nonNull(categGrop) ? categGrop.get(vo.getServCategId() + "-" + vo.getCategOneId() + "-" + vo.getCategId()) : null);
            vo.setFicoCtegName(Objects.nonNull(categMap) ? ficoCategMap.get(vo.getFicoCtegId()) : null);
            vo.setChannelName(Objects.nonNull(categMap) ? channelMap.get(vo.getChannelId()) : null);
            productBaseDROList.add(vo);
        });
        return productBaseDROList;
    }

    /**
     * 渠道产品或者渠道开通通用产品的对应的服务分类下的产品
     *
     * @param list      产品列表
     * @param channelId 渠道id
     * @param showType  产品类型
     */
    private List<ProductAllMsgVO> filterChannelProductOrOpenCategory(List<ProductAllMsgVO> list, Integer channelId, Integer showType) {
        if (NumberUtil.isNotNullOrZero(channelId) && !Objects.equals(GlobalConsts.YES, showType)) {
            List<Integer> servCategIds = channelGeneralProductSwitchService.listServCateIdByChannelAndStatus(channelId, GlobalConsts.NO);
            //去除失效的产品，和没有关联服务分类的通用产品
            List<ProductAllMsgVO> notInServList = list.stream()
                    .filter(x -> !servCategIds.contains(x.getServCategId()) && Objects.equals(GlobalConsts.NO, x.getProductType()))
                    .collect(Collectors.toList());
            List<ProductAllMsgVO> channelGeneralList = list.stream()
                    .filter(x -> Objects.equals(channelId, x.getChannelId()) && Objects.equals(GlobalConsts.YES, x.getProductType()))
                    .collect(Collectors.toList());
            list = ListUtils.union(notInServList, channelGeneralList);


        }
        if (NumberUtil.isNotNullOrZero(channelId)) {
            List<Integer> channelServProducts = Optional.ofNullable(
                            channelServProductService.listProductIdByChannelId(channelId).stream().filter(x -> Objects.equals(GlobalConsts.NO, x.getStatus()))
                                    .map(ChannelServProduct::getProductId)
                                    .collect(Collectors.toList()))
                    .orElse(Collections.emptyList());
            list = list.stream().filter(x -> !channelServProducts.contains(x.getProductId())).collect(Collectors.toList());
        }
        return list;

    }

    /**
     * 渠道开通通用产品的对应的服务分类下的默认产品
     *
     * @param list        产品列表
     * @param channelId   渠道id
     * @param showType    产品类型
     * @param defaultType 是否是默认
     */

    private List<ProductAllMsgVO> filterChannelOpenCategoryByDefaultProducts(List<ProductAllMsgVO> list, Integer channelId, Integer showType, Integer defaultType) {
        if (NumberUtil.isNotNullOrZero(channelId) && Objects.equals(GlobalConsts.YES, showType) && Objects.equals(GlobalConsts.YES, defaultType)) {
            List<Integer> productIds = servProductRelationService.listProductIdByServProductStatus(GlobalConsts.YES);
            //去除失效的产品，和没有关联服务分类的通用产品
            List<ProductAllMsgVO> channelGeneralList = list.stream()
                    .filter(x -> productIds.contains(x.getServCategId()) && Objects.equals(channelId, x.getChannelId()))
                    .collect(Collectors.toList());

            List<Integer> servCategIds = channelGeneralProductSwitchService.listServCateIdByChannelAndStatus(channelId, GlobalConsts.NO);
            //去除失效的产品，和没有关联服务分类的通用产品
            List<ProductAllMsgVO> notInServList = list.stream()
                    .filter(x -> !servCategIds.contains(x.getServCategId()) && Objects.equals(GlobalConsts.NO, x.getProductType()))
                    .collect(Collectors.toList());
            list = ListUtils.union(notInServList, channelGeneralList);
        }
        return list;
    }

    /**
     * 如果是查询前台产品，则需要对应开通的后台产品也开通了当前业务类型
     *
     * @param list        产品列表
     * @param bizType     业务类型
     * @param showType    产品类型
     * @param defaultType 是否是默认
     */

    private List<ProductAllMsgVO> filterBizType(List<ProductAllMsgVO> list, Integer bizType, Integer showType, Integer defaultType) {
        if (NumberUtil.isNotNullOrZero(bizType) && Objects.equals(GlobalConsts.YES, showType) && !Objects.equals(GlobalConsts.YES, defaultType)) {
            List<Integer> productIds = servProductRelationService.listProductIdByServProductBizType(bizType);
            //去除失效的产品，和没有关联服务分类的通用产品
            list = list.stream()
                    .filter(x -> productIds.contains(x.getProductId()))
                    .collect(Collectors.toList());
        }
        // 如果是查询计价器产品，则需要对应开通的后台产品也开通了当前业务类型
        if (NumberUtil.isNotNullOrZero(bizType) && Objects.equals(3, showType)) {
            List<Integer> ids = servTariffProductRelationService.listTarifProductIdsByBizType(bizType);
            list = list.stream().filter(x -> ids.contains(x.getProductId())).collect(Collectors.toList());
        }
        return list;
    }
}
